TailsNS.HTMLTemplate = {
  apply: function(obj, doc) {
    this._applyChildren(obj, doc.body);
  },

  /*
   * INTERNAL FUNCTIONS
   */
  _applyChildren: function(obj, parent) {
    for (var i=0; i<parent.childNodes.length; i++) {
      var child = parent.childNodes[i];
      if (child.hasChildNodes && child.tagName) {
        this._applyNode(obj, child);
      }
    }
  },
  
  _applyNode: function(obj, node) {
    var processChildren = true;
    if (node.id) {
      var pathString = (node.id[0] == '_') ? node.id.substring(1) : node.id;

      var path = pathString.split(':');
      var value = obj;
      for (var i=0; i<path.length; i++) {
        if (!value) break;
        if (path[i] != 'this') {
          var next = value[path[i]];
          if (typeof(next) == 'function') {
            value = value[path[i]]();
          } else
            value = value[path[i]];
        }
      }
      
      if (node.id[0] != '_' || value == null) {
        processChildren = false;
        var hideIfNull = true;
        
        var classAttr = node.getAttribute('class');
        if (value != null && classAttr && this['_format_'+classAttr]) {
          var result = this['_format_'+classAttr](value, node);
          if (typeof(result) == 'string') {
            value = result;
          } else {
            value = result[0];
            if (result[1] != null) hideIfNull = result[1];
          }
        }
      
        //alert(node.id + '=' + value);
      
        if (value != null) {
          this._setNodeValue(node, value);

        } else if (hideIfNull) {
          node.style.display = 'none';
        }
      }
    }
    
    if (processChildren && node.hasChildNodes && node.tagName) {
      this._applyChildren(obj, node);
    }
  },
  _setNodeValue: function(node, value) {
    var children = node.childNodes;
    if (children.length == 0 || (children.length == 1
        && children[0].nodeName == '#text' && children[0].data.match(/^\s*$/))) {
      node.innerHTML = value;
    } else {
      for (var i=0; i<children.length; i++) {
        if (children[i].nodeName == '#text') {
          var text = children[i].data;
          var tok = text.indexOf('%');
          if (tok >= 0) {
            var doc = node.ownerDocument;
            var postSubText = null;
            if (tok < text.length-1) {
              postSubText = doc.createTextNode(text.substring(tok+1));
            }
            children[i].data = text.substring(0, tok);
            var span = doc.createElement('span');
            span.innerHTML = value;
            if (children[i].nextSibling) {
              var pos = children[i].nextSibling;
              doc.insertBefore(span,pos);
              if (postSubText) doc.insertBefore(postSubText, pos);
            } else {
              children[i].parentNode.appendChild(span);
              if (postSubText) children[i].parentNode.appendChild(postSubText);
            }
          }
        }
      }
    }
  },
  
  _walkElements: function(node, func) {
    for (var i=0; i<node.childNodes.length; i++) {
      var child = node.childNodes[i];
      if (child.hasChildNodes && child.tagName) {
        var r = func(child);
        if (r == true) {
          r = this._walkElements(child, func);
          if (r) return r;
        } else if (r != false) {
          return r;
        }
      }
    }
  },
  
  _format_img: function(value, node) {
    return '<img src="' + value + '"/>';
  },
  _format_href: function(value, node) {
    return '<a href="' + value + '" target="_blank">' + value + '</a>';
  },
  _format_email: function(value, node) {
    return '<a href="mailto:' + value + '">' + value + '</a>';
  },
  _format_timestamp: function(value, node) {
    return FormatBase.prettyDate(value, "%A, %B %d, %Y %H:%M");
  },
  _format_date: function(value, node) {
    return FormatBase.months[value.getMonth()] + " " + value.getDate() + ", " + value.getFullYear();
  },
  _format_array: function(value, node) {
    var func = function(node) {
      if (node.getAttribute('class') && node.getAttribute('class') == 'each') {
        return node;
      }
      return true;
    };
    //alert(node.id + ": " + value.length);
    var eachNode = this._walkElements(node, func);
    var parentNode = eachNode.parentNode;
    parentNode.removeChild(eachNode);
    for (var i=0; i<value.length; i++) {
      var n = eachNode.cloneNode(true);
      parentNode.appendChild(n);
      var o = {};
      o[node.id] = value[i];
      this._applyNode(o, n);
    }
    return [null, false];
  }
};